﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Data.Services.Client;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Microsoft.Samples.ServiceHosting.StorageClient;
using System.Data.SqlClient;

namespace CCS
{
    [Serializable]
    public class CCSEntitySaveException : Exception
    {
        private const string DefaultMessage = "Failed to save the entity";

        public CCSEntitySaveException()
            : base(DefaultMessage)
        {
        }

        public CCSEntitySaveException(string message)
            : base(message)
        {
        }

        public CCSEntitySaveException(string message, Exception inner)
            : base(message, inner)
        {
        }

        protected CCSEntitySaveException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }

    public static class Procedures
    {
        #region Private Methods (Helper Methods)

        public static IEnumerable<T> Get<T>(TableStorageDataServiceContext serviceContext, Dictionary<string, object> values)
        {
            IList<T> retval = new List<T>();
            ReadOnlyCollection<EntityDescriptor> entities = serviceContext.Entities;
            var list = serviceContext.GetType().GetProperties().Where(p => p.PropertyType == typeof(IQueryable<T>)).First().GetValue(serviceContext, null) as IEnumerable<T>;
            foreach (T item in list)
            {
                var matches = new List<bool>();
                foreach (var value in values)
                {
                    string valueKey = value.Key;
                    object valueValue = value.Value;
                    IEnumerable<PropertyInfo> props = item.GetType().GetProperties().Where(p => p.Name.Equals(valueKey, StringComparison.InvariantCultureIgnoreCase));
                    object itemValue = props.First().GetValue(item, null);
                    if (itemValue.Equals(valueValue))
                    {
                        matches.Add(true);
                    }
                    else
                    {
                        matches.Add(false);
                    }
                }
                if (!matches.Contains(false))
                {
                    retval.Add(item);
                }
            }

            return retval;
        }

        public static bool Save<T>(this T entity, TableStorage tableStorage, string tableName, string entitySetName) where T : TableStorageEntity
        {
            bool retval = false;
            tableStorage.TryCreateTable(tableName);
            TableStorageDataServiceContext context = tableStorage.GetDataServiceContext();
            context.AddObject(entitySetName, entity);
            context.SaveChangesWithRetries();
            retval = entity.HasValidTimestamp();
            return retval;
        }

        public static bool Update<T>(this T entity, TableStorage tableStorage, string entitySetName) where T : TableStorageEntity
        {
            bool retval = false;
            TableStorageDataServiceContext context = tableStorage.GetDataServiceContext();
            context.AttachTo(entitySetName, entity, "*");
            context.UpdateObject(entity);
            context.SaveChangesWithRetries();
            retval = entity.HasValidTimestamp();
            return retval;
        }

        public static bool Delete<T>(this T entity, TableStorage tableStorage, string entitySetName) where T : TableStorageEntity
        {
            bool retval = false;
            TableStorageDataServiceContext context = tableStorage.GetDataServiceContext();
            context.AttachTo(entitySetName, entity, "*");
            context.DeleteObject(entity);
            context.SaveChangesWithRetries();
            return true;
        }

        #endregion

        #region Public Methods (Client Methods?)

        public static CCSUser AddUserInfo(StorageAccountInfo accountInfo, TableStorage tableStorage, string lastname, string firstname, string address, string city, string state, string zip, string phone, string email, Guid devToken, string productName, string licenseLevel, string uniqueMachineID)
        {
            CCSUser retval = default(CCSUser);

            var productServiceContext = new CCSProductServiceContext(accountInfo);
            CCSProduct product = productServiceContext.CCSProducts.Where(p => p.PartitionKey == CCSProduct.TableName && p.ProductName.Equals(productName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

            var licensLevelProductContext = new CCSLicenseLevelPriceServiceContext(accountInfo);
            CCSLicenseLevelPrice licenseLevelPrice = licensLevelProductContext.CCSLicenseLevelPrices.Where(l => l.PartitionKey == CCSLicenseLevelPrice.TableName && l.LicenseLevel.Equals(licenseLevel)).FirstOrDefault();

            if (product != null && licenseLevelPrice != null)
            {
                retval = new CCSUser(CCSUser.TableName, Extensions.DefaultRowKey().ToString()) { LicenseLevelID = licenseLevelPrice.LicenseID, ProductID = product.ID, UniqueMachineID = uniqueMachineID, UserCity = city, UserDate = DateTime.Now, UserDevToken = devToken, UserEmail = email, UserFirstName = firstname, UserLastName = lastname, UserID = Guid.NewGuid(), UserPhone = phone, UserState = state, UserStreet = address, UserZip = zip };
            }

            bool saved = retval.Save(tableStorage, CCSUser.TableName, CCSUser.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }

        public static int GetAllowedInvoiceCount(StorageAccountInfo accountInfo, TableStorage tableStorage, string invoice)
        {
            IEnumerable<CCSLicenseTransaction> licenseTransaction = Get<CCSLicenseTransaction>(new CCSLicenseTransactionServiceContext(accountInfo), new Dictionary<string, object> { { "Invoice", invoice } });
            IEnumerable<CCSProduct> product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ID", licenseTransaction.First().ProductID } });
            return product.Single().LicensesPerInvoice;
        }

        public static int GetApprovedInvoiceCount(StorageAccountInfo accountInfo, string invoice)
        {
            var licenseTransactionServiceContext = new CCSLicenseTransactionServiceContext(accountInfo);
            IQueryable<CCSLicenseTransaction> licenseTransactions = licenseTransactionServiceContext.CCSLicenseTransactions.Where(lt => lt.LicenseResponse == "approved" && lt.Invoice == invoice);
            return licenseTransactions.ToArray().Length;
        }

        public static CCSProductConfigSettings GetProductConfigSettings(StorageAccountInfo accountInfo, string productName, Guid devToken)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "DevToken", devToken } }).Single();
            var productConfigSettingsServiceContext = new CCSProductConfigSettingsServiceContext(accountInfo);
            return productConfigSettingsServiceContext.CCSProductConfigSettings.Where(c => c.DevToken == devToken && c.ProductID == product.ID).Single();
        }

        public static CCSProductDataStore GetProductDataStoreSettings(StorageAccountInfo accountInfo, Guid devToken, string productName, string uniqueMachineId)
        {
            var productServiceContext = new CCSProductServiceContext(accountInfo);
            CCSProduct product = productServiceContext.CCSProducts.Where(p => p.DevToken == devToken && p.ProductName == productName).First();
            var productDataStoreServiceContext = new CCSProductDataStoreServiceContext(accountInfo);
            var productDataStore = productDataStoreServiceContext.CCSProductDataStores.Where(p => p.DevToken == devToken && p.ProductID == product.ID && p.UniqueMachineID == uniqueMachineId).FirstOrDefault();
            return productDataStore;
        }

        public static CCSLicenseLevelPrice GetProductLicenseLevels(StorageAccountInfo accountInfo, string productName, Guid devToken)
        {
            CCSLicenseLevelPrice retval = default(CCSLicenseLevelPrice);
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName } }).Single();
            var licenseLevelPriceServiceContext = new CCSLicenseLevelPriceServiceContext(accountInfo);
            retval = licenseLevelPriceServiceContext.CCSLicenseLevelPrices.Where(l => l.ProductID == product.ID && l.DevToken == devToken).First();
            return retval;
        }

        public static CCSPaymentSettings GetProductPaymentSettings(StorageAccountInfo accountInfo, Guid devToken)
        {
            return Get<CCSPaymentSettings>(new CCSPaymentSettingsServiceContext(accountInfo), new Dictionary<string, object> { { "DevToken", devToken } }).Single();
        }

        public static CCSProductDataStore InitializeProductDataStoreSettings(TableStorage tableStorage, StorageAccountInfo accountInfo, Guid devToken, DateTime dateTime, string productName, string licenseLevel, int numberOfTrialDaysElapsed, string registrationKey, DateTime startDate, bool userInfoRegistered, string uniqueMachineID)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName } }).Single();
            CCSLicenseLevelPrice licenseLevelPrice = GetProductLicenseLevels(accountInfo, productName, devToken);
            var productDataStore = new CCSProductDataStore(CCSProductDataStore.TableName, Extensions.DefaultRowKey().ToString()) { DateTime = DateTime.Now, DevToken = devToken, LicenseID = licenseLevelPrice.LicenseID, DataStoreID = Guid.NewGuid(), NumberOfTrialDaysElapsed = numberOfTrialDaysElapsed, ProductID = product.ID, RegistrationKey = registrationKey, StartDate = startDate, UniqueMachineID = uniqueMachineID, UserInfoRegistered = userInfoRegistered };
            bool saved = productDataStore.Save(tableStorage, CCSProductDataStore.TableName, CCSProductDataStore.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return productDataStore;
        }

        public static CCSProduct InsertNewProduct(TableStorage tableStorage, string productName, DateTime productReleaseDate, string productVersion, int licensePerInvoice, int buyNowMaxPoll, int activateNowMaxPoll, int trialLengthDays, int abortTimerLength, int pollingTimerLength, Guid devToken)
        {
            CCSProduct retval = default(CCSProduct);

            // Create new CCSProduct
            Guid productId = Extensions.DefaultRowKey();
            retval = new CCSProduct(CCSProduct.TableName, productId.ToString()) { ID = productId, ProductName = productName, ProductReleaseDate = productReleaseDate, ProductVersion = productVersion, LicensesPerInvoice = licensePerInvoice, DevToken = devToken };
            bool saved = retval.Save(tableStorage, CCSProduct.TableName, CCSProduct.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            // Create new CCSProductConfigSettings
            var configSettings = new CCSProductConfigSettings(CCSProductConfigSettings.TableName, Extensions.DefaultRowKey().ToString()) { ProductID = retval.ID, AbortTimerLength = abortTimerLength, ActivateNowMaxNumPoll = activateNowMaxPoll, BuyNowMaxNumPoll = buyNowMaxPoll, PollingTimerLength = pollingTimerLength, TrialLengthDays = trialLengthDays, DevToken = devToken };
            saved = configSettings.Save(tableStorage, CCSProductConfigSettings.TableName, CCSProductConfigSettings.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            // Create three CCSLicenseLevelPrices for CCSProduct
            var sharewareLicenseLevel = new CCSLicenseLevelPrice(CCSLicenseLevelPrice.TableName, Extensions.DefaultRowKey().ToString()) { LicenseID = Properties.Settings.Default.SharewareLicenseLevelId, ProductID = retval.ID, LicenseLevel = "Shareware", LicenseLevelPrice = 0, DevToken = devToken, TrialLicenseKey = true, ClientID = 0, Description = "This is the default trial license key" };
            saved = sharewareLicenseLevel.Save(tableStorage, CCSLicenseLevelPrice.TableName, CCSLicenseLevelPrice.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            var premiumLicenseLevel = new CCSLicenseLevelPrice(CCSLicenseLevelPrice.TableName, Extensions.DefaultRowKey().ToString()) { LicenseID = Properties.Settings.Default.PremiumLicenseLevelId, ProductID = retval.ID, LicenseLevel = "Premium", LicenseLevelPrice = 0, DevToken = devToken, TrialLicenseKey = false, ClientID = 1, Description = "This is the default premium license key" };
            saved = premiumLicenseLevel.Save(tableStorage, CCSLicenseLevelPrice.TableName, CCSLicenseLevelPrice.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            var standardLicenseLevel = new CCSLicenseLevelPrice(CCSLicenseLevelPrice.TableName, Extensions.DefaultRowKey().ToString()) { LicenseID = Properties.Settings.Default.StandardLicenseLevelId, ProductID = retval.ID, LicenseLevel = "Standard", LicenseLevelPrice = 0, DevToken = devToken, TrialLicenseKey = false, ClientID = 2, Description = "This is the default standard license key" };
            saved = standardLicenseLevel.Save(tableStorage, CCSLicenseLevelPrice.TableName, CCSLicenseLevelPrice.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }

        public static PaymentTransaction InvoiceInPaymentTransaction(StorageAccountInfo accountInfo, string invoice)
        {
            PaymentTransactionServiceContext paymentTransactionService = new PaymentTransactionServiceContext(accountInfo);
            var paymentTransactions = paymentTransactionService.PaymentTransactions;

            CCSLicenseTransactionServiceContext licenseTransactionService = new CCSLicenseTransactionServiceContext(accountInfo);
            var licenseTransactions = licenseTransactionService.CCSLicenseTransactions;

            CCSLicenseLevelPriceServiceContext licenseLevelPriceService = new CCSLicenseLevelPriceServiceContext(accountInfo);
            var licenseLevelPrices = licenseLevelPriceService.CCSLicenseLevelPrices;

            var paymentTransaction = paymentTransactions.Where(p => p.Invoice == invoice).FirstOrDefault();
            var licenseTransaction = licenseTransactions.Where(lt => lt.Invoice == invoice).FirstOrDefault();
            var licenseLevelPrice = licenseLevelPrices.Where(ll => ll.ProductID == licenseTransaction.ProductID && licenseTransaction.ProductLicenseLevelID == ll.LicenseID && paymentTransaction.McGross == ll.LicenseLevelPrice);

            return paymentTransaction;
        }

        public static IEnumerable<CCSCoupon> IsInvoiceACoupon(StorageAccountInfo accountInfo, string invoice, Guid devToken)
        {
            var couponServiceContext = new CCSCouponServiceContext(accountInfo);
            return couponServiceContext.CCSCoupons.Where(c => c.Coupon_number == new Guid(invoice) && c.DevToken == devToken);
        }

        public static void MarkInvoice(TableStorage tableStorage, StorageAccountInfo accountInfo, string invoice, string result)
        {
            CCSLicenseTransaction licenseTransaction = Get<CCSLicenseTransaction>(new CCSLicenseTransactionServiceContext(accountInfo), new Dictionary<string, object> { { "Invoice", invoice } }).Single();
            licenseTransaction.LicenseResponse = result;
            bool updated = licenseTransaction.Update(tableStorage, CCSLicenseTransaction.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }
        }

        public static PaymentCustInfo Payment_Insert_CustInfo(TableStorage tableStorage, Guid id, string address1, string address2, string addressName, string addressStatus, string businessName, string city, string country, string dayPhoneA, string dayPhoneB, string dayPhoneC, string email, string firstName, string lastName, string nightPhoneA, string nightPhoneB, string nightPhoneC, string payerID, string payerStatus, string state, string zip)
        {
            var retval = new PaymentCustInfo(PaymentCustInfo.TableName, Extensions.DefaultRowKey().ToString()) { ID = id, Address1 = address1, Address2 = address2, AddressName = addressName, AddressStatus = addressStatus, BusinessName = businessName, City = city, Country = country, DayPhoneA = dayPhoneA, DayPhoneB = dayPhoneB, DayPhoneC = dayPhoneC, Email = email, FirstName = firstName, LastName = lastName, NightPhoneA = nightPhoneA, NightPhoneB = nightPhoneB, NightPhoneC = nightPhoneC, PayerID = payerID, PayerStatus = payerStatus, State = state, Zip = zip };
            bool saved = retval.Save(tableStorage, PaymentCustInfo.TableName, PaymentCustInfo.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }

        public static PaymentShoppingItems Payment_Insert_Shopping_Items(TableStorage tableStorage, Guid id, string itemName, string itemNumber, string option1FieldName, string option1Values, string option2FieldName, string option2Values)
        {
            var retval = new PaymentShoppingItems(PaymentShoppingItems.TableName, Extensions.DefaultRowKey().ToString()) { ID = id, ItemName = itemName, ItemNumber = itemNumber, Option1FieldName = option1FieldName, Option2FieldName = option2FieldName, Option1Values = option1Values, Option2Values = option2Values };
            bool saved = retval.Save(tableStorage, PaymentShoppingItems.TableName, PaymentShoppingItems.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }
            return retval;
        }

        public static PaymentTransaction Payment_Insert_Transaction(TableStorage tableStorage, DateTime receivedDateTime, string business, string custom, string invoice, string mcCurrency, double mcFee, double mcGross, string memo, DateTime paymentDate, string paymentStatus, string paymentType, string pendingReason, string receiverEmail, string ReceiverID, int recurTimes, double settleAmount, string settleCurrency, double tax, string transactionID, string transactionType)
        {
            var retval = new PaymentTransaction(PaymentTransaction.TableName, Extensions.DefaultRowKey().ToString()) { ID = Guid.NewGuid(), Business = business, DeveloperToken = new Guid(custom), Invoice = invoice, McCurrency = mcCurrency, McFee = mcFee, McGross = mcGross, Memo = memo, PaymentDate = paymentDate, PaymentStatus = paymentStatus, PaymentType = paymentType, PendingReason = pendingReason, ReceivedDateTime = receivedDateTime, ReceiverEmail = receiverEmail, RecurTimes = recurTimes, SettleAmount = settleAmount, SettleCurrency = settleCurrency, Tax = tax, TransactionID = transactionID, TransactionType = transactionType };
            bool saved = retval.Save(tableStorage, PaymentTransaction.TableName, PaymentTransaction.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }

        public static PaymentTransactionRelated Payment_Insert_Transaction_Related(TableStorage tableStorage, Guid id, double exchangeRate, string ipnVersion, string isRecurring, string option1FieldName, string option1Selection, string option2FieldName, string option2Selection, string password, string rawIPN, string reasonCode, string reattemptFailedPayments, DateTime retryFailedPaymentsDates, string username, string verifySign)
        {
            var retval = new PaymentTransactionRelated(PaymentTransactionRelated.TableName, Extensions.DefaultRowKey().ToString()) { ID = id, ExchangeRate = exchangeRate, IPNVersion = ipnVersion, IsRecurring = isRecurring, Option1FieldName = option1FieldName, Option2FieldName = option2FieldName, Option1Selection = option1Selection, Option2Selection = option2Selection, RawIPN = rawIPN, ReasonCode = reasonCode, Password = password, ReattemptFailedPayments = reattemptFailedPayments, ReattemptFailedPaymentsDate = retryFailedPaymentsDates, Username = username, VerifySign = verifySign };
            bool saved = retval.Save(tableStorage, PaymentTransactionRelated.TableName, PaymentTransactionRelated.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }
            return retval;
        }

        public static PaymentCustInfo SendMailApprovedLicense(TableStorage tableStorage, StorageAccountInfo accountInfo, string invoice)
        {
            PaymentTransaction paymentTransactionInvoice = Get<PaymentTransaction>(new PaymentTransactionServiceContext(accountInfo), new Dictionary<string, object> { { "invoice", invoice } }).Single();
            PaymentCustInfo paymentCustInfo = Get<PaymentCustInfo>(new PaymentCustInfoServiceContext(accountInfo), new Dictionary<string, object> { { "ID", paymentTransactionInvoice.ID } }).Single();
            return paymentCustInfo;
        }

        public static void SetCouponDate(TableStorage tableStorage, StorageAccountInfo accountInfo, string invoice)
        {
            CCSCoupon coupon = Get<CCSCoupon>(new CCSCouponServiceContext(accountInfo), new Dictionary<string, object> { { "Coupon_number", new Guid(invoice) } }).Single();
            coupon.Used_date = DateTime.UtcNow;
            bool updated = coupon.Update(tableStorage, CCSCoupon.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }
        }

        public static void StoreAuthLicense(TableStorage tableStorage, StorageAccountInfo accountInfo, string invoice, string authLicense)
        {
            CCSLicenseTransaction licenseTransaction = Get<CCSLicenseTransaction>(new CCSLicenseTransactionServiceContext(accountInfo), new Dictionary<string, object> { { "Invoice", invoice } }).FirstOrDefault();
            licenseTransaction.AuthLicense = authLicense;
            bool updated = licenseTransaction.Update(tableStorage, CCSLicenseTransaction.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }
        }

        public static CCSLicenseTransaction StoreLicenseTransaction(TableStorage tableStorage, string invoice, string clientIdentity, Guid product, Guid licenseLevel, Guid devToken, string serialClientID)
        {
            var retval = new CCSLicenseTransaction(CCSLicenseTransaction.TableName, Extensions.DefaultRowKey().ToString()) { AuthLicense = null, ClientID = clientIdentity, Invoice = invoice, ProductID = product, LicenseResponse = null, ProductLicenseLevelID = licenseLevel, SerialClientID = serialClientID, TransDate = DateTime.Now, DevToken = devToken, ID = Guid.NewGuid() };
            bool saved = retval.Save(tableStorage, CCSLicenseTransaction.TableName, CCSLicenseTransaction.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }

        public static CCSException SubmitException(TableStorage tableStorage, string message, string source, string stacktrace, string methodName, string productName, Guid devToken, string licenseLevel, string uniqueMachineID)
        {
            var retval = new CCSException(CCSException.TableName, Extensions.DefaultRowKey().ToString()) { DevToken = devToken, ExceptionDateTime = DateTime.Now, ExceptionID = Guid.NewGuid(), Message = message, MethodName = methodName, Source = source, StackTrace = stacktrace, UniqueMachineID = uniqueMachineID };
            bool saved = retval.Save(tableStorage, CCSException.TableName, CCSException.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }
            return retval;
        }

        public static CCSIssue SubmitIssue(TableStorage tableStorage, StorageAccountInfo accountInfo, string productName, string licenseLevel, string emailContact, string firstName, string lastName, string description, Guid devToken, string uniqueMachineID)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName }, { "DevToken", devToken } }).Single();
            CCSLicenseLevelPrice licenseLevelPrice = Get<CCSLicenseLevelPrice>(new CCSLicenseLevelPriceServiceContext(accountInfo), new Dictionary<string, object> { { "LicenseLevel", licenseLevel }, { "ProductId", product.ID }, { "DevToken", devToken } }).Single();
            var retval = new CCSIssue(CCSIssue.TableName, Extensions.DefaultRowKey().ToString()) { IssueDate = DateTime.Now, IssueLastName = lastName, IssueFirstName = firstName, IssueDevToken = devToken, IssueDescription = description, IssueEmailContact = emailContact, IssueUniqueMachineID = uniqueMachineID, IssueLicenseLevelID = licenseLevelPrice.LicenseID, IssueID = Guid.NewGuid(), IssueProductID = product.ID };
            bool saved = retval.Save(tableStorage, CCSIssue.TableName, CCSIssue.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }
            return retval;
        }

        public static CCSProductDataStore FindOrCreateProductDataStore(TableStorage tableStorage, StorageAccountInfo accountInfo, Guid devToken, Guid productId, Guid licenseId, bool isRegistered, string uniqueMachineID)
        {
            var licenseLevelPrice = Get<CCSLicenseLevelPrice>(new CCSLicenseLevelPriceServiceContext(accountInfo), new Dictionary<string, object> { { "ProductID", productId }, { "LicenseID", licenseId } }).Single();
            var productDataStoreServiceContext = new CCSProductDataStoreServiceContext(accountInfo);
            CCSProductDataStore productDataStore = productDataStoreServiceContext.CCSProductDataStores.Where(p => p.DevToken == devToken && p.ProductID == productId && p.UniqueMachineID == uniqueMachineID).FirstOrDefault();
            if (productDataStore == null)
            {
                productDataStore = new CCSProductDataStore(CCSProductDataStore.TableName, Extensions.DefaultRowKey().ToString())
                                       {
                                           LicenseID = licenseId,
                                           DataStoreID = Guid.NewGuid(),
                                           DevToken = devToken,
                                           DateTime = DateTime.Now,
                                           NumberOfTrialDaysElapsed = 0,
                                           ProductID = productId,
                                           StartDate = DateTime.Now,
                                           UniqueMachineID = uniqueMachineID,
                                           Timestamp = DateTime.UtcNow,
                                           UserInfoRegistered = isRegistered,
                                           RegistrationKey = "Shareware"
                                       };
                bool saved = productDataStore.Save(tableStorage, CCSProductDataStore.TableName, CCSProductDataStore.TableName);
                if (!saved)
                {
                    throw new CCSEntitySaveException();
                }
            }
            return productDataStore;
        }

        public static bool UpdateDataStoreRegistration(TableStorage tableStorage, StorageAccountInfo accountInfo, Guid devToken, string productName, string uniqueMachineID, bool isRegistered, string licenseLevel)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName } }).Single();

            CCSLicenseLevelPrice licenseLevelPrice = Get<CCSLicenseLevelPrice>(new CCSLicenseLevelPriceServiceContext(accountInfo), new Dictionary<string, object> { { "LicenseLevel", licenseLevel }, { "ProductID", product.ID } }).Single();

            CCSProductDataStore productDataStore = FindOrCreateProductDataStore(tableStorage, accountInfo, devToken, product.ID, licenseLevelPrice.LicenseID, isRegistered, uniqueMachineID);
            productDataStore.UserInfoRegistered = isRegistered;
            bool updated = productDataStore.Update(tableStorage, CCSProductDataStore.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }
            return updated;
        }

        public static void UpdateDataStoreRegistrationKey(TableStorage tableStorage, StorageAccountInfo accountInfo, Guid devToken, string productName, string registrationKey, string licenseLevel)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName } }).Single();

            var licenseLevelPriceServiceContext = new CCSLicenseLevelPriceServiceContext(accountInfo);
            CCSLicenseLevelPrice licenseLevelPrice = licenseLevelPriceServiceContext.CCSLicenseLevelPrices.Where(l => l.LicenseLevel == licenseLevel && l.ProductID == product.ID).First();

            //var productDataStoreServiceContext = new CCSProductDataStoreServiceContext(accountInfo);
            //var productDataStores = Get<CCSProductDataStore>(new CCSProductDataStoreServiceContext(accountInfo), new Dictionary<string, object> { { "DevToken", devToken }, { "ProductID", product.ID }, { "LicenseID", licenseLevelPrice.LicenseID } });

            CCSProductDataStore productDataStore = FindOrCreateProductDataStore(tableStorage, accountInfo, devToken, product.ID, licenseLevelPrice.LicenseID, true, string.Empty);

            productDataStore.RegistrationKey = registrationKey;

            bool updated = productDataStore.Update(tableStorage, CCSProductDataStore.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }
        }

        #endregion

        #region Public Methods (Administrative Methods?)

        public static CCSPaymentSettings CreatePaymentSettings(TableStorage tableStorage, Guid devToken, string accountEmail, string itemNumber, int quantity, string currencycode, string notifyURL, bool requireShippingAddress, bool includeNote, string logoURL, string tag, string noteTitle, string successUrl, string cancelUrl, string payment_url)
        {
            var retval = new CCSPaymentSettings(CCSPaymentSettings.TableName, Extensions.DefaultRowKey().ToString()) { DevToken = devToken, Payment_URL = payment_url, PayPal_AccountEmail = accountEmail, PayPal_cancelURL = cancelUrl, PayPal_currencyCode = currencycode, PayPal_includeNote = includeNote, PayPal_ItemNumber = itemNumber, PayPal_logoURL = logoURL, PayPal_noteTitle = noteTitle, PayPal_notifyURL = notifyURL, PayPal_Quantity = quantity, PayPal_requireShippingAddress = requireShippingAddress, PayPal_successUrl = successUrl, PayPal_tag = tag };
            bool saved = retval.Save(tableStorage, CCSPaymentSettings.TableName, CCSPaymentSettings.TableName);
            if (!saved)
            {
                throw new CCSEntitySaveException();
            }

            return retval;
        }


        public static CCSLicenseLevelPrice GetTrialLicenseLevel(StorageAccountInfo accountInfo, string productName, Guid devToken)
        {
            CCSProduct product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ProductName", productName }, { "DevToken", devToken } }).Single();
            return Get<CCSLicenseLevelPrice>(new CCSLicenseLevelPriceServiceContext(accountInfo), new Dictionary<string, object> { { "ProductID", product.ID }, { "DevToken", devToken }, { "TrialLicenseKey", true } }).Single();
        }


        public static int PaymentCompletedTransactions(StorageAccountInfo accountInfo)
        {
            var paymentTransactionServiceContext = new PaymentTransactionServiceContext(accountInfo);
            IQueryable<PaymentTransaction> completedPaymentTransactions = paymentTransactionServiceContext.PaymentTransactions.Where(p => p.PaymentStatus == "completed");
            var paymentShoppingItemsServiceContext = new PaymentShoppingItemsServiceContext(accountInfo);
            int retval = 0;
            foreach (PaymentShoppingItems psi in paymentShoppingItemsServiceContext.PaymentShoppingItems)
            {
                Guid psiID = psi.ID;
                retval += completedPaymentTransactions.Where(c => c.ID == psiID).ToArray().Length;
            }
            return retval;
        }

        public static bool UpdateProductSettings(TableStorage tableStorage, StorageAccountInfo accountInfo, string productName, DateTime productReleaseDate, string productVersion, int licensesPerInvoice, Guid productId, int buyNowMaxPoll, int activateNowMaxPool, int trialLengthDays, int abortTimerLength, int pollingTimerLength)
        {
            CCSProductConfigSettings productConfigSettings = Get<CCSProductConfigSettings>(new CCSProductConfigSettingsServiceContext(accountInfo), new Dictionary<string, object> { { "ProductID", productId } }).Single();
            productConfigSettings.BuyNowMaxNumPoll = buyNowMaxPoll;
            productConfigSettings.ActivateNowMaxNumPoll = activateNowMaxPool;
            productConfigSettings.TrialLengthDays = trialLengthDays;
            productConfigSettings.AbortTimerLength = abortTimerLength;
            productConfigSettings.PollingTimerLength = pollingTimerLength;
            bool updated = productConfigSettings.Update(tableStorage, CCSProductConfigSettings.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }

            var product = Get<CCSProduct>(new CCSProductServiceContext(accountInfo), new Dictionary<string, object> { { "ID", productId } }).FirstOrDefault();
            product.ProductName = productName;
            product.ProductReleaseDate = productReleaseDate;
            product.ProductVersion = productVersion;
            updated = product.Update(tableStorage, CCSProduct.TableName);
            if (!updated)
            {
                throw new CCSEntitySaveException();
            }

            return true;
        }

        public class PaymentCompletedTransaction
        {
            public PaymentCompletedTransaction(string itemName, string itemNumber, decimal gross, decimal fee)
            {
                ItemName = itemName;
                ItemNumber = itemNumber;
                Gross = gross;
                Fee = fee;
            }

            public string ItemName { get; private set; }
            public string ItemNumber { get; private set; }
            public decimal Gross { get; private set; }
            public decimal Fee { get; private set; }
        }

        #endregion

        public static bool VerifyLicenseAvailableInDB(string clientIdentity, ref Guid licenseLevel, Guid product, string invoice, Guid devToken)
        {
            return InvoiceInPaypalTransaction(invoice);
        }

        /// <summary>
        /// InvoiceInPaypalTransaction returns true if the invoice argument
        /// is found in a transaction inside the Paypal_Transaction table.  
        /// Returns false if it's not found in the Paypal_Transaction table.
        /// </summary>
        /// <param name="invoice">Invoice ID generated by the client</param>
        /// <returns>true - invoice found in Paypal_Transaction table record</returns>
        public static bool InvoiceInPaypalTransaction(string invoice)
        {
            bool inPaypal = false;
            ////SqlDataReader reader = SqlHelper.ExecuteReader(ConfigurationManager.AppSettings["SQLConnectionString"], "InvoiceInPaymentTransaction", invoice);

            StorageAccountInfo accountInfo = StorageClientHelper.GetAccountInfo();
            TableStorage tableStorage = StorageClientHelper.GetTableStorage();
            inPaypal = InvoiceInPaymentTransaction(accountInfo, invoice) != null;

            /*

            if (reader.HasRows)
            {
                inPaypal = true;
                reader.Read();

                string paymentStatus = (string)reader["PaymentStatus"];
                string pendingReason = (string)reader["PendingReason"];

                switch (paymentStatus)
                {
                    case "Completed":
                        return true;

                        break;
                    case "Pending":

                        switch (pendingReason)
                        {
                            case "Echeck":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["EcheckMessage"]);


                            case "Multi-Currency":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Intl":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Verify":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Address":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Upgrade":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Unilateral":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                            case "Other":
                                throw new PaypalException(
                                    ConfigurationManager.AppSettings["Problem"].Replace(
                                    "*invoice*", invoice)
                                    );


                        }

                        break;
                    case "Failed":
                        throw new PaypalException(
                            ConfigurationManager.AppSettings["Problem"].Replace(
                            "*invoice*", invoice)
                            );

                        break;
                    case "Denied":
                        throw new PaypalException(
                            ConfigurationManager.AppSettings["Problem"].Replace(
                            "*invoice*", invoice)
                            );

                        break;
                    case "Refunded":
                        inPaypal = false;
                        break;
                    case "Cancelled":
                        inPaypal = false;
                        break;
                    default:
                        inPaypal = false;
                        break;
                }

            }
            else
            {
                Logger.Log("GetLicense : InvoiceInPaypalTransactipn : Reader has no rows ");
            }
            Logger.Log("GetLicense : InvoiceInPaypalTransactipn : Completed");

            */

            return inPaypal;
        }

        public static void UpdateDataStoreRegistrationKey(TableStorage tableStorage, StorageAccountInfo accountInfo, Guid devToken, Guid product, string p, Guid licenseLevel)
        {
            throw new NotImplementedException();
        }

        public static IEnumerable<CCSProduct> GetAllProducts(StorageAccountInfo accountInfo)
        {
            CCSProductServiceContext productServiceContext = new CCSProductServiceContext(accountInfo);
            return productServiceContext.CCSProducts;
        }
    }
}